package com.net.client;

import com.net.client.entity.ClientProperties;
import com.net.common.util.ValidatorUtils;
import com.net.common.entity.Message;
import com.net.common.exception.NetRuntimeException;
import com.net.common.util.MessageSerializableUtils;
import com.net.common.util.ThreadPoolFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Optional;

import static com.net.common.constant.Constant.CONNECT;
import static com.net.common.constant.Constant.MessageType.ERROR;
import static com.net.common.constant.Constant.MessageType.INTERNAL;
import static com.net.common.constant.Constant.TIME_OUT;

/**
 * 客户端启动类
 *
 * @author hjh
 */

public class Client extends Socket {

    private static final Logger log = LoggerFactory.getLogger(Client.class);

    public static final ClientProperties clientProperties = new ClientProperties();

    private static final String HTTP_ADDRESS = "代理地址为-> http://";

    /**
     * 一个客户端一个sessionId
     */
    public static Long sessionId;

    static {
        // 初始化
        clientProperties.loadResources(Client.class.getResourceAsStream("/client.properties"), clientProperties);
    }

    private Client(String ip, int port) throws IOException {
        super(ip, port);
    }

    public static void main(String[] args) {
        Client client;
        try {
            if (!ValidatorUtils.validate(clientProperties.getLocalIp(), clientProperties.getLocalPort())) {
                throw new NetRuntimeException("内网连接不可用");
            }

            log.info("正在连接服务器  -----------------------");
            client = new Client(clientProperties.getServerIp(), clientProperties.getServerPort());
            log.info("成功连接服务器  ------------------------");
            // 与服务的进行握手
            MessageSerializableUtils.sendSerializableMessage(client.getOutputStream(), () -> new Message(INTERNAL, CONNECT.getBytes(StandardCharsets.UTF_8), new HashMap<>()));
            // 监听消息
            Message message = MessageSerializableUtils.listenerSerializableMessage(client.getInputStream());
            if (ERROR.equals(message.getMessageType())) {
                throw new NetRuntimeException(new String(message.getBody(), StandardCharsets.UTF_8));
            }

            sessionId = message.getSessionId();
            // 超时时间(如果服务器与客户端长时间未通信这客户端自动关闭连接)
            client.setSoTimeout(Integer.parseInt(message.getHeaderMap().get(TIME_OUT)));

            log.info(HTTP_ADDRESS + clientProperties.getServerIp() + ":" + message.getHeaderMap().get("port") + ",超时时间为-> {}毫秒", Integer.parseInt(message.getHeaderMap().get(TIME_OUT)));

            ListenerMessage listenerMessage = new ListenerMessage(client);
            // 定时检测内网服务是否可用,主要防止客户端一直占用服务器资源
            listenerMessage.scheduleConnectionListener();
            // 监听服务端的消息
            listenerMessage.messageListener();
        } catch (Exception e) {
            log.error("客户端异常推出:{}", Optional.ofNullable(e.getCause()).map(Throwable::getMessage).orElse(e.getMessage()));
        } finally {
            // 监听结束要终止所有线程
            ThreadPoolFactory.shutdown();
        }
    }
}
